﻿using Common;
using UnityEngine;
using UnityEngine.Rendering;

///////////////////////////////////////////////////////////
//
//  Written by              ：laishikai
//  Copyright(C)            ：成都博瑞梦工厂
//  ------------------------------------------------------
//  功能描述                ：角色伤害数字渲染管理模块
//
///////////////////////////////////////////////////////////

    
public enum EHUDRenderType
{
    /// <summary>
    /// 普通伤害
    /// </summary>
    [InspectorName("普通伤害")]
    NORMAL_ATTACK = 1,

    /// <summary>
    /// 加血
    /// </summary>
    [InspectorName("加血")]
    ADD_HP = 2,
    
    /// <summary>
    /// 加蓝
    /// </summary>
    [InspectorName("加蓝")]
    ADD_MP = 3,
        
    /// <summary>
    /// 持续伤害-中毒
    /// </summary>
    [InspectorName("持续伤害-中毒")]
    DOT_POISON = 4,
        
    /// <summary>
    /// 持续伤害-灼烧
    /// </summary>
    [InspectorName("持续伤害-灼烧")]
    DOT_BURN = 5,
        
    /// <summary>
    /// 持续伤害-感电
    /// </summary>
    [InspectorName("持续伤害-感电")]
    DOT_ELECTRICITY = 6,
        
    /// <summary>
    /// 持续伤害-流血
    /// </summary>
    [InspectorName("持续伤害-流血")]
    DOT_BLEED = 7,
        
    /// <summary>
    /// 暴击
    /// </summary>
    [InspectorName("暴击")]
    CRIT = 8,
        
    /// <summary>
    /// 格挡
    /// </summary>
    [InspectorName("格挡")]
    BLOCK = 9,
        
    /// <summary>
    /// MISS
    /// </summary>
    [InspectorName("MISS")]
    MISS = 10,

    /// <summary>
    /// 护盾吸收伤害
    /// </summary>
    [InspectorName("护盾吸收")]
    ShieldAbsorbDamage = 11,

    [InspectorName("免死")]
    ImmuneDeath = 12,

    [InspectorName("重生")]
    Reborn = 13,
};

class HUDNumberEntry
{
    public Transform m_tf;
    public HUDNumberEntry m_pNext;
    public int m_nAnimAttrIdx;
    public Vector3 m_vPos; // 对象的世界坐标
    public Vector2 m_vMove;  // 位移
    public float m_fAniScale;  // 动画缩放
    public float m_fScale;
    public float m_fAlpha;  // 半透
    public BetterList<HUDVertex> m_aSprite = new BetterList<HUDVertex>(); // 对应的图片ID
    public int m_nWidth = 0; // 宽度
    public int m_nHeight = 0;
    public int m_nSpriteGap = 0;
    public float m_fStartTime = 0.0f;
    public bool m_bStop = false;
    public float m_offsetX = 0.0f;
    public float m_offsetY = 0.0f;
    public float m_otherScale = 1f;
    
    public void reset()
    {
        m_tf = null;
        m_vPos = Vector3.zero;
        m_vMove = Vector2.zero;
        m_fScale = 1.0f;
        m_fAniScale = 1.0f;
        m_fAlpha = 1.0f;
        ReleaseVertex();
        m_nWidth = 0;
        m_nHeight = 0;
        m_nSpriteGap = 0;
        m_bStop = false;
        m_offsetX = 0.0f;
        m_offsetY = 0.0f;
    }
    
    public void ReleaseVertex()
    {
        for(int i = m_aSprite.size - 1; i >= 0; --i)
        {
            HUDVertex v = m_aSprite[i];
            if (v.hudMesh != null)
                v.hudMesh.EraseHUDVertex(v);
            v.hudMesh = null;
            HUDVertex.ReleaseVertex(v);
            m_aSprite[i] = null;
        }
        m_aSprite.Clear();
    }

    // 功能：更新屏幕位置
    public bool UpdateScreenPos( ref HudAnimAttribute attrib)
    {
        if (attrib.ScreenAlign)
            return false;

        if(m_tf != null)
        {
            Vector3 vPos = m_tf.position;
            Vector3 v = vPos - m_vPos;
            if(v.x * v.x + v.y * v.y + v.z * v.z > 0.00001f)
            {
                Camera caMain = HUDMesh.GetHUDMainCamera();
                if(caMain != null)
                {
                    m_vPos = vPos;
                    Vector3 vCameraPos = caMain.transform.position;
                    CaleCameraScale(vCameraPos);
                    return true;
                }
            }
        }
        return false;
    }

    public void CaleCameraScale(Vector3 vCameraPos)
    {
        Vector3 vPos = m_vPos;
        float m_nearDistance = HUDMgr.Instance.HUDSetting.CameraNearDist;
        float m_farDistance = HUDMgr.Instance.HUDSetting.CameraFarDist;
        float m_minScale = HUDMgr.Instance.HUDSetting.m_fNumberScaleMin;
        float m_maxScale = HUDMgr.Instance.HUDSetting.m_fNumberScaleMax;
        float dis = Vector3.Distance(vPos, vCameraPos);
        float ratio = Mathf.Clamp01((dis - m_nearDistance) / (m_farDistance - m_nearDistance));
        float fScale = m_minScale * ratio + (1.0f - ratio) * m_maxScale;
        m_fScale = 1.0f / fScale;
    }

    public void PushSprite(float y, int nSpriteID)
    {
        HUDVertex node = HUDVertex.QueryVertex();
        node.WorldPos = m_vPos;
        node.Offset.Set(m_nWidth, y);
        node.SpriteID = nSpriteID;
        node.InitSprite();
        m_aSprite.Add(node);
        m_nWidth += node.width + m_nSpriteGap;
        if (m_nHeight < node.height)
            m_nHeight = node.height;
    }
    public void MakeLeft()
    {
        m_nWidth -= m_nSpriteGap;
        MoveAll(0.0f);
    }
    // 居中
    public void MakeCenter()
    {
        m_nWidth -= m_nSpriteGap;
        float fHalfW = m_nWidth * 0.5f;
        MoveAll(fHalfW);
    }
    // 右对齐
    public void MakeRight()
    {
        m_nWidth -= m_nSpriteGap;
        float fMoveX = m_nWidth;
        MoveAll(fMoveX);
    }
    void  MoveAll(float fMoveX)
    {
        float fHalfH = m_nHeight * 0.5f;
        for (int i = 0, nSize = m_aSprite.size; i < nSize; ++i)
        {
            float fH = m_aSprite[i].height;
            m_aSprite[i].Offset.x -= fMoveX;
            m_aSprite[i].Offset.y -= fH * 0.5f - fHalfH;
        }
    }
};

class HUDSprtieSetting
{
    public int m_nHeadID; // 开头的图片ID
    public int m_nAddID;  // + 号
    public int m_nSubID;  // - 号
    public int[] m_NumberID = null; // 数字ID
    public void InitNumber(string szHeadName, string szPrefix)
    {
        CAtlasMng pMng = CAtlasMng.instance;
        if (!string.IsNullOrEmpty(szHeadName))
        {
            m_nHeadID = pMng.SpriteNameToID(szHeadName);
        }
        else
        {
            m_nHeadID = 0;
        }
        if (!string.IsNullOrEmpty(szPrefix))
        {
            m_NumberID = new int[10];
            m_nAddID = pMng.SpriteNameToID(szPrefix + "+");
            m_nSubID = pMng.SpriteNameToID(szPrefix + '-');
            for (int i = 0; i < 10; ++i)
            {
                m_NumberID[i] = pMng.SpriteNameToID(szPrefix + i.ToString());
            }
        }
    }
};

public class HUDNumberRender
{
    bool m_bInit = false;
    bool m_bCanUpdateLogic = false;
    bool m_bAddCommandBuffer = false;
    float m_fLastUpdateLogicTime = 0.0f;

    HudAnimAttribute[] m_aTtribute;
    HUDNumberEntry m_aInvalid;
    HUDSprtieSetting[] m_Settings;
    float m_fDurationTime = 2.0f; // 动画持续时间

    HUDNumberEntry m_ValidList;
    BetterList<int> m_tempNumb = new BetterList<int>();
    HUDRender m_MeshRender = new HUDRender();
    bool m_bMeshDirty = false;
    bool m_bCaleScreenScale = false;
    float m_fScreenScaleX = 1.0f;
    float m_fScreenScaleY = 1.0f;

    private bool m_bHudNumberVisible;

    Camera m_oldCamera;

    Camera m_renderCamera;
    CommandBuffer s_cmdBuffer = new CommandBuffer(){name = "Damage Number"};

    public void InitHUDSetting(HUDSetting hudSetting)
    {
        m_aTtribute = hudSetting.NumberAttibute;
        m_fDurationTime = hudSetting.m_fDurationTime;
        m_bHudNumberVisible = true;
    }

    public void OnLeaveGame()
    {
        while(m_ValidList != null)
        {
            HUDNumberEntry pDel = m_ValidList;
            m_ValidList = m_ValidList.m_pNext;
            OnErase(pDel);
        }
        ReleaseCommandBuffer();
        m_MeshRender.Release();
    }

    void ReleaseCommandBuffer()
    {
        if (m_bAddCommandBuffer)
        {
            m_bAddCommandBuffer = false;
            RenderFunctionSlot.GetDamageNumberCommandBufferFunction = null;
            m_renderCamera = null;
            s_cmdBuffer.Clear();
        }
    }

    public bool HUDNumberVisible
    {
        set
        {
            if (m_bHudNumberVisible != value)
            {
                if (!value)
                {
                    CleanCurrentNumber();
                    ReleaseCommandBuffer();
                }
            }
            m_bHudNumberVisible = value;
        }
        get { return m_bHudNumberVisible; }
    }
    
    void CleanCurrentNumber()
    {
        while (m_ValidList != null)
        {
            HUDNumberEntry pDel = m_ValidList;
            m_ValidList = m_ValidList.m_pNext;
            pDel.m_pNext = null;
            OnErase(pDel);
        }
        m_bMeshDirty = true;
    }

    void InitHUD()
    {
        m_aTtribute = HUDMgr.Instance.HUDSetting.NumberAttibute;

        int nNumber = m_aTtribute.Length;

        m_Settings = new HUDSprtieSetting[nNumber];
        for (int i = 0; i < nNumber; ++i)
        {
            m_Settings[i] = new HUDSprtieSetting();

            m_Settings[i].InitNumber(m_aTtribute[i].szHeadName, m_aTtribute[i].szPrefix);
        }        
    }
    
    HUDNumberEntry  QueryHudNumber(int animAttrIdx)
    {
        HUDNumberEntry pNode = m_aInvalid;
        if (pNode != null)
        {
            m_aInvalid = pNode.m_pNext;
            pNode.m_pNext = null;
        }
        if (pNode == null)
        {
            pNode = new HUDNumberEntry();
            pNode.m_nAnimAttrIdx = animAttrIdx;
        }
        return pNode;
    }

    void  ReleaseHudNumber(HUDNumberEntry pNode)
    {
        if (pNode != null)
        {
            pNode.m_pNext = m_aInvalid;
            m_aInvalid = pNode;
        }
    }

    bool m_bPuase = false;
    float m_currentDuration = 0.0f;
    
    // 功能：执行数字的动画效果
    void PlayAnimation(HUDNumberEntry pNode, bool bFirst, float m_fOldScale = 0, float m_offseteX =0, float m_offsetY = 0)
    {
        int nIndex = pNode.m_nAnimAttrIdx;
        float currentDuration = (Time.time - pNode.m_fStartTime);
        if (m_bPuase)
            currentDuration = m_currentDuration;
        HudAnimAttribute attrib = m_aTtribute[nIndex];
        bool bDirty = false;
        float fAlpha = attrib.AlphaCurve.Evaluate(currentDuration);                 //淡出效果;
        float fScale = attrib.ScaleCurve.Evaluate(currentDuration);   //变大效果;
        float fPos = attrib.MoveCurve.Evaluate(currentDuration);                    //Y轴移动效果;
        float fOldAlpha = pNode.m_fAlpha;
        float fOldScale = pNode.m_fAniScale;
        float fOldMoveX = pNode.m_vMove.x;
        float fOldMoveY = pNode.m_vMove.y;
        float fOffsetX = attrib.OffsetX;
        float fotherScale = 1;

        if (m_offseteX != 0)
        {
            fOffsetX = m_offseteX;
            pNode.m_offsetX = fOffsetX;
        }
        else if (pNode.m_offsetX != fOffsetX)
        {
            fOffsetX = pNode.m_offsetX;
        }
        
        float fOffsetY = attrib.OffsetY;
        if (m_offsetY != 0)
        {
            fOffsetY = m_offsetY;
            pNode.m_offsetY = fOffsetY;
        }
        else if (pNode.m_offsetY != fOffsetY)
        {
            fOffsetY = pNode.m_offsetY;
        }
        
        if (m_fOldScale != 0)
        {
            fotherScale = m_fOldScale;
            pNode.m_otherScale = m_fOldScale;
        }
        else if (pNode.m_otherScale != fotherScale)
        {
            fotherScale = pNode.m_otherScale;
        }

        pNode.m_fAlpha = fAlpha;
        pNode.m_fAniScale = fScale;
        if(attrib.ScreenAlign)
        {
            pNode.m_vMove.x = 0.0f;
            pNode.m_vMove.y = fPos * m_fScreenScaleY;
        }
        else
        {
            pNode.m_vMove.x = fOffsetX * m_fScreenScaleX;
            pNode.m_vMove.y = (fOffsetY + fPos) * m_fScreenScaleY;
        }
        pNode.m_bStop = currentDuration > m_fDurationTime;
        if (m_bPuase)
            pNode.m_bStop = false;

        int nAlpha = (int)(fAlpha * 255.0f + 0.5f);
        if (nAlpha < 0)
            nAlpha = 0;
        if (nAlpha > 255)
            nAlpha = 255;
        byte alpha = (byte)nAlpha;
        
        if (!bFirst)
            bDirty = pNode.UpdateScreenPos(ref attrib);
        else
            bDirty = true;

        if(!bDirty)
        {
            if (Mathf.Abs(fOldAlpha - pNode.m_fAlpha) > 0.0001f)
                bDirty = true;
            if (!bDirty && Mathf.Abs(fOldScale - pNode.m_fScale) > 0.0001f)
                bDirty = true;
            if (!bDirty && Mathf.Abs(fOldMoveX - pNode.m_vMove.x) > 0.0001f)
                bDirty = true;
            if (!bDirty && Mathf.Abs(fOldMoveY - pNode.m_vMove.y) > 0.0001f)
                bDirty = true;
        }
        if (!bDirty)
            return;

        fScale *= pNode.m_fScale * fotherScale;

        // 更新顶点数据
        Vector2 vMove = pNode.m_vMove;
        for (int i = pNode.m_aSprite.size - 1; i>=0; --i)
        {
            HUDVertex v = pNode.m_aSprite[i];
            v.Move  = vMove;
            v.WorldPos = pNode.m_vPos;
            v.Scale = fScale;
            v.clrLU.a = alpha;
            v.clrLD.a = alpha;
            v.clrRU.a = alpha;
            v.clrRD.a = alpha;
            v.hudMesh.VertexDirty();
        }
    }
    
    void  OnPush(HUDNumberEntry pNode)
    {
        for(int i = 0; i<pNode.m_aSprite.size; ++i)
        {
            HUDMesh hudMesh = m_MeshRender.QueryMesh(pNode.m_aSprite[i].AtlasID);
            pNode.m_aSprite[i].hudMesh = hudMesh;
            hudMesh.PushHUDVertex(pNode.m_aSprite[i]);
        }
    }
    void  OnErase(HUDNumberEntry pNode)
    {
        // 释放模型的数据吧
        pNode.ReleaseVertex();
        ReleaseHudNumber(pNode);
    }
    
    void  FillMeshRender()
    {
        m_MeshRender.FillMesh();
        if (m_MeshRender.m_bMeshDirty)
            m_bMeshDirty = true;
        if(!m_bMeshDirty)
        {
            Camera caMain = HUDMesh.GetHUDMainCamera();
            if(caMain != m_oldCamera)
            {
                m_oldCamera = caMain;
                m_bMeshDirty = true;
            }
        }

        if(m_bMeshDirty)
        {
            m_bMeshDirty = false;
            if(m_renderCamera != null)
            {
                RenderFunctionSlot.GetDamageNumberCommandBufferFunction = null;
                m_renderCamera = null;
                m_bAddCommandBuffer = false;
            }
            Camera caMain = HUDMesh.GetHUDMainCamera();
            s_cmdBuffer.Clear();
            if (caMain == null || !m_bHudNumberVisible)
                return;
            m_MeshRender.RenderTo(s_cmdBuffer);
            if(s_cmdBuffer.sizeInBytes > 0 && caMain != null)
            {
                m_renderCamera = caMain;
                RenderFunctionSlot.GetDamageNumberCommandBufferFunction = GetCurCommandBuffer;
                m_bAddCommandBuffer = true;
            }
        }
    }

    private CommandBuffer GetCurCommandBuffer()
    {
        return s_cmdBuffer;
    }
    
    void CaleScreenScale()
    {
        m_bCaleScreenScale = true;
        m_fScreenScaleX = 1080 / 1280.0f;
        m_fScreenScaleY = 1920 / 720.0f;
        m_fScreenScaleX *= HUDMesh.s_fNumberScale;
        m_fScreenScaleY *= HUDMesh.s_fNumberScale;
    }

    public void UpdateLogic(float delta)
    {
        if (!m_bCanUpdateLogic)
        {
            return;
        }
        
        // 计算屏幕的缩放
        CaleScreenScale();

        HUDNumberEntry pNode = m_ValidList;
        HUDNumberEntry pLast = m_ValidList;
        while (pNode != null)
        {
            PlayAnimation(pNode, false);
            if(pNode.m_bStop)
            {
                HUDNumberEntry pDel = pNode;
                if (pNode == m_ValidList)
                {
                    m_ValidList = m_ValidList.m_pNext;
                    pLast = m_ValidList;
                }
                else
                {
                    pLast.m_pNext = pNode.m_pNext;
                }
                pNode = pNode.m_pNext;
                OnErase(pDel);                
                continue;
            }
            pLast = pNode;
            pNode = pNode.m_pNext;
        }
        if (m_ValidList == null)
            m_bMeshDirty = true;

        FillMeshRender();
        if (m_ValidList == null)
        {
            if(m_fLastUpdateLogicTime + 5.0f < Time.time)
            {
                m_bCanUpdateLogic = false;
            }
            CleanAllMeshRender();
        }
        else
        {
            m_fLastUpdateLogicTime = Time.time;
        }
    }

    // 功能：清除所有的模型渲染
    void CleanAllMeshRender()
    {
        m_MeshRender.FastClearVertex(); // CleanAllVertex
        ReleaseCommandBuffer();
    }

    // 功能：添加一个显示的数字
    public void  AddHUDNumber(Transform tf, int nType, int nNumber, Vector3 pos, bool bShowAdd, bool bShowSub, float tempScale)
    {
        if (!m_bHudNumberVisible)
            return;
        
        Camera caMain = HUDMesh.GetHUDMainCamera();
        if (caMain == null)
            return;
        
        // 未定义的HUD类型
        var animAttrIdx = -1;
        for (var i = 0; i < m_aTtribute.Length; ++i)
        {
            if ((int)m_aTtribute[i].HUDRenderType == nType)
            {
                animAttrIdx = i;
                break;
            }
        }
        if (animAttrIdx < 0)
        {
            return;
        }

        HudAnimAttribute attrib = m_aTtribute[animAttrIdx];

        if (!m_bInit)
        {
            m_bInit = true;
            InitHUD();
        }
        
        Vector3 vPos = pos;
        if (tf)
        {
            vPos = tf.position;
        }

        m_bCanUpdateLogic = true;
        m_bMeshDirty = true;

        HUDNumberEntry pNode = QueryHudNumber(animAttrIdx);
        pNode.m_nAnimAttrIdx = animAttrIdx;
        pNode.m_pNext = m_ValidList;
        m_ValidList = pNode;

        if(nNumber < 0)
        {
            bShowSub = true;
            nNumber = -nNumber;
        }

        pNode.reset();

        // 初始化
        pNode.m_nSpriteGap = attrib.SpriteGap;
        pNode.m_fStartTime = Time.time;
        pNode.m_tf = tf;
        pNode.m_vPos = vPos;
        
        // 如果按屏幕对齐
        if (attrib.ScreenAlign)
        {
            Vector3 v1 = caMain.WorldToScreenPoint(vPos);
            v1.x = attrib.OffsetX;
            v1.y = attrib.OffsetY;
            float fScaleX = 1080 / 1280.0f;
            float fScaleY = 1920 / 1280.0f;

            if (attrib.ScreenAlignType == HUDAlignType.align_left)
            {
                v1.x = attrib.OffsetX;
                v1.y = attrib.OffsetY;
            }
            else if(attrib.ScreenAlignType == HUDAlignType.align_right)
            {
                v1.x = 1280.0f - attrib.OffsetX;
                v1.y = attrib.OffsetY;
            }
            else
            {
                v1.x = 1080 / 2.0f + attrib.OffsetX;
                v1.y = attrib.OffsetY;
            }
            v1.x *= fScaleX;
            v1.y *= fScaleY;

            vPos = caMain.ScreenToWorldPoint(v1);
            pNode.m_vPos = vPos;

            Vector3 vCameraPos = caMain.transform.position;
            pNode.CaleCameraScale(vCameraPos);
        }
        else
        {
            Vector3 vCameraPos = caMain.transform.position;
            pNode.CaleCameraScale(vCameraPos);
        }

        float y = 0.0f;
        HUDSprtieSetting pSetting = m_Settings[animAttrIdx];
        if(pSetting.m_nHeadID != 0)
        {
            pNode.PushSprite(y, pSetting.m_nHeadID);
        }

        if (pSetting.m_NumberID!=null)
        {
            if (bShowAdd && pSetting.m_nAddID != 0)
            {
                pNode.PushSprite(y, pSetting.m_nAddID);
            }
            else if (bShowSub && pSetting.m_nSubID != 0)
            {
                pNode.PushSprite(y, pSetting.m_nSubID);
            }
            m_tempNumb.Clear();
            int nI = 0;
            do
            {
                nI = nNumber % 10;
                nNumber /= 10;
                m_tempNumb.Add(nI);
            } while (nNumber > 0);
            // 反转数组
            m_tempNumb.Reverse();
            for (int i = 0, nSize = m_tempNumb.size; i < nSize; ++i)
            {
                nI = m_tempNumb[i];
                pNode.PushSprite(y, pSetting.m_NumberID[nI]);
            }
        }
        // 居中处理吧
        switch(attrib.AlignType)
        {
            case HUDAlignType.align_right:
                pNode.MakeRight();
                break;
            case HUDAlignType.align_center:
                pNode.MakeCenter();
                break;
            default:
                pNode.MakeLeft();
                break;
        }
        
        // 申请纹理
        OnPush(pNode);

        if(!m_bCaleScreenScale)
        {
            CaleScreenScale();
        }
        float scWidthScale = 1080 / 1080f;
        float offsetX = Random.Range(attrib.OffsetRangXMin, attrib.OffsetRangXMax);
        float offsetY = Random.Range(attrib.OffsetRangYMin, attrib.OffsetRangYMax) * scWidthScale;
        PlayAnimation(pNode, true,tempScale * scWidthScale, offsetX,offsetY);
    }
}
